home *** CD-ROM | disk | FTP | other *** search
/ Risc World 3 / Risc World 3.iso / SOFTWARE / ISSUE6 / PD / PDF / xpdf / c++ / gfile < prev    next >
Text File  |  2003-02-21  |  15KB  |  722 lines

  1. //========================================================================
  2. //
  3. // gfile.cc
  4. //
  5. // Miscellaneous file and directory name manipulation.
  6. //
  7. // Copyright 1996-2002 Glyph & Cog, LLC
  8. //
  9. //========================================================================
  10.  
  11. //========================================================================
  12. //
  13. // Changes marked:
  14. //
  15. //   //**** Colin Granville ****
  16. // To
  17. //   //**** end Colin Granville ****
  18. //
  19. // made by Colin Granville 2003
  20. //
  21. //========================================================================
  22.  
  23. #include <aconf.h>
  24.  
  25. #ifdef WIN32
  26.    extern "C" {
  27. #  ifndef _MSC_VER
  28. #    include <kpathsea/win32lib.h>
  29. #  endif
  30.    }
  31. #else // !WIN32
  32. #  if defined(MACOS)
  33. #    include <sys/stat.h>
  34. #  elif !defined(ACORN)
  35. #    include <sys/types.h>
  36. #    include <sys/stat.h>
  37. #    include <fcntl.h>
  38. #  endif
  39. #  include <limits.h>
  40. #  include <string.h>
  41. #  if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
  42. #    include <pwd.h>
  43. #  endif
  44. #  if defined(VMS) && (__DECCXX_VER < 50200000)
  45. #    include <unixlib.h>
  46. #  endif
  47. #endif // WIN32
  48. #include "GString.h"
  49. #include "gfile.h"
  50.  
  51. // Some systems don't define this, so just make it something reasonably
  52. // large.
  53. #ifndef PATH_MAX
  54. #define PATH_MAX 1024
  55. #endif
  56.  
  57. //------------------------------------------------------------------------
  58.  
  59. GString *getHomeDir() {
  60. #ifdef VMS
  61.   //---------- VMS ----------
  62.   return new GString("SYS$LOGIN:");
  63.  
  64. #elif defined(__EMX__) || defined(WIN32)
  65.   //---------- OS/2+EMX and Win32 ----------
  66.   char *s;
  67.   GString *ret;
  68.  
  69.   if ((s = getenv("HOME")))
  70.     ret = new GString(s);
  71.   else
  72.     ret = new GString(".");
  73.   return ret;
  74.  
  75. #elif defined(ACORN)
  76.   //---------- RISCOS ----------
  77.   return new GString("@");
  78.  
  79. #elif defined(MACOS)
  80.   //---------- MacOS ----------
  81.   return new GString(":");
  82.  
  83. #else
  84.   //---------- Unix ----------
  85.   char *s;
  86.   struct passwd *pw;
  87.   GString *ret;
  88.  
  89.   if ((s = getenv("HOME"))) {
  90.     ret = new GString(s);
  91.   } else {
  92.     if ((s = getenv("USER")))
  93.       pw = getpwnam(s);
  94.     else
  95.       pw = getpwuid(getuid());
  96.     if (pw)
  97.       ret = new GString(pw->pw_dir);
  98.     else
  99.       ret = new GString(".");
  100.   }
  101.   return ret;
  102. #endif
  103. }
  104.  
  105. GString *getCurrentDir() {
  106.   char buf[PATH_MAX+1];
  107.  
  108. #if defined(__EMX__)
  109.   if (_getcwd2(buf, sizeof(buf)))
  110. #elif defined(WIN32)
  111.   if (GetCurrentDirectory(sizeof(buf), buf))
  112. #elif defined(ACORN)
  113.   if (strcpy(buf, "@"))
  114. #elif defined(MACOS)
  115.   if (strcpy(buf, ":"))
  116. #else
  117.   if (getcwd(buf, sizeof(buf)))
  118. #endif
  119.     return new GString(buf);
  120.   return new GString();
  121. }
  122.  
  123. GString *appendToPath(GString *path, char *fileName) {
  124. #if defined(VMS)
  125.   //---------- VMS ----------
  126.   //~ this should handle everything necessary for file
  127.   //~ requesters, but it's certainly not complete
  128.   char *p0, *p1, *p2;
  129.   char *q1;
  130.  
  131.   p0 = path->getCString();
  132.   p1 = p0 + path->getLength() - 1;
  133.   if (!strcmp(fileName, "-")) {
  134.     if (*p1 == ']') {
  135.       for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
  136.       if (*p2 == '[')
  137.     ++p2;
  138.       path->del(p2 - p0, p1 - p2);
  139.     } else if (*p1 == ':') {
  140.       path->append("[-]");
  141.     } else {
  142.       path->clear();
  143.       path->append("[-]");
  144.     }
  145.   } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
  146.     if (*p1 == ']') {
  147.       path->insert(p1 - p0, '.');
  148.       path->insert(p1 - p0 + 1, fileName, q1 - fileName);
  149.     } else if (*p1 == ':') {
  150.       path->append('[');
  151.       path->append(']');
  152.       path->append(fileName, q1 - fileName);
  153.     } else {
  154.       path->clear();
  155.       path->append(fileName, q1 - fileName);
  156.     }
  157.   } else {
  158.     if (*p1 != ']' && *p1 != ':')
  159.       path->clear();
  160.     path->append(fileName);
  161.   }
  162.   return path;
  163.  
  164. #elif defined(WIN32)
  165.   //---------- Win32 ----------
  166.   GString *tmp;
  167.   char buf[256];
  168.   char *fp;
  169.  
  170.   tmp = new GString(path);
  171.   tmp->append('/');
  172.   tmp->append(fileName);
  173.   GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
  174.   delete tmp;
  175.   path->clear();
  176.   path->append(buf);
  177.   return path;
  178.  
  179. #elif defined(ACORN)
  180.   //---------- RISCOS ----------
  181.   char *p;
  182.   int i;
  183.  
  184.   path->append(".");
  185.   i = path->getLength();
  186.   path->append(fileName);
  187.   for (p = path->getCString() + i; *p; ++p) {
  188.     if (*p == '/') {
  189.       *p = '.';
  190.     } else if (*p == '.') {
  191.       *p = '/';
  192.     }
  193.   }
  194.   return path;
  195.  
  196. #elif defined(MACOS)
  197.   //---------- MacOS ----------
  198.   char *p;
  199.   int i;
  200.  
  201.   path->append(":");
  202.   i = path->getLength();
  203.   path->append(fileName);
  204.   for (p = path->getCString() + i; *p; ++p) {
  205.     if (*p == '/') {
  206.       *p = ':';
  207.     } else if (*p == '.') {
  208.       *p = ':';
  209.     }
  210.   }
  211.   return path;
  212.  
  213. #elif defined(__EMX__)
  214.   //---------- OS/2+EMX ----------
  215.   int i;
  216.  
  217.   // appending "." does nothing
  218.   if (!strcmp(fileName, "."))
  219.     return path;
  220.  
  221.   // appending ".." goes up one directory
  222.   if (!strcmp(fileName, "..")) {
  223.     for (i = path->getLength() - 2; i >= 0; --i) {
  224.       if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
  225.       path->getChar(i) == ':')
  226.     break;
  227.     }
  228.     if (i <= 0) {
  229.       if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
  230.     path->del(1, path->getLength() - 1);
  231.       } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
  232.     path->del(2, path->getLength() - 2);
  233.       } else {
  234.     path->clear();
  235.     path->append("..");
  236.       }
  237.     } else {
  238.       if (path->getChar(i-1) == ':')
  239.     ++i;
  240.       path->del(i, path->getLength() - i);
  241.     }
  242.     return path;
  243.   }
  244.  
  245.   // otherwise, append "/" and new path component
  246.   if (path->getLength() > 0 &&
  247.       path->getChar(path->getLength() - 1) != '/' &&
  248.       path->getChar(path->getLength() - 1) != '\\')
  249.     path->append('/');
  250.   path->append(fileName);
  251.   return path;
  252.  
  253. #else
  254.   //---------- Unix ----------
  255.   int i;
  256.  
  257.   // appending "." does nothing
  258.   if (!strcmp(fileName, "."))
  259.     return path;
  260.  
  261.   // appending ".." goes up one directory
  262.   if (!strcmp(fileName, "..")) {
  263.     for (i = path->getLength() - 2; i >= 0; --i) {
  264.       if (path->getChar(i) == '/')
  265.     break;
  266.     }
  267.     if (i <= 0) {
  268.       if (path->getChar(0) == '/') {
  269.     path->del(1, path->getLength() - 1);
  270.       } else {
  271.     path->clear();
  272.     path->append("..");
  273.       }
  274.     } else {
  275.       path->del(i, path->getLength() - i);
  276.     }
  277.     return path;
  278.   }
  279.  
  280.   // otherwise, append "/" and new path component
  281.   if (path->getLength() > 0 &&
  282.       path->getChar(path->getLength() - 1) != '/')
  283.     path->append('/');
  284.   path->append(fileName);
  285.   return path;
  286. #endif
  287. }
  288.  
  289. GString *grabPath(char *fileName) {
  290. #ifdef VMS
  291.   //---------- VMS ----------
  292.   char *p;
  293.  
  294.   if ((p = strrchr(fileName, ']')))
  295.     return new GString(fileName, p + 1 - fileName);
  296.   if ((p = strrchr(fileName, ':')))
  297.     return new GString(fileName, p + 1 - fileName);
  298.   return new GString();
  299.  
  300. #elif defined(__EMX__) || defined(WIN32)
  301.   //---------- OS/2+EMX and Win32 ----------
  302.   char *p;
  303.  
  304.   if ((p = strrchr(fileName, '/')))
  305.     return new GString(fileName, p - fileName);
  306.   if ((p = strrchr(fileName, '\\')))
  307.     return new GString(fileName, p - fileName);
  308.   if ((p = strrchr(fileName, ':')))
  309.     return new GString(fileName, p + 1 - fileName);
  310.   return new GString();
  311.  
  312. #elif defined(ACORN)
  313.   //---------- RISCOS ----------
  314.   char *p;
  315.  
  316.   if ((p = strrchr(fileName, '.')))
  317.     return new GString(fileName, p - fileName);
  318.   return new GString();
  319.  
  320. #elif defined(MACOS)
  321.   //---------- MacOS ----------
  322.   char *p;
  323.  
  324.   if ((p = strrchr(fileName, ':')))
  325.     return new GString(fileName, p - fileName);
  326.   return new GString();
  327.  
  328. #else
  329.   //---------- Unix ----------
  330.   char *p;
  331.  
  332.   if ((p = strrchr(fileName, '/')))
  333.     return new GString(fileName, p - fileName);
  334.   return new GString();
  335. #endif
  336. }
  337.  
  338. GBool isAbsolutePath(char *path) {
  339. #ifdef VMS
  340.   //---------- VMS ----------
  341.   return strchr(path, ':') ||
  342.      (path[0] == '[' && path[1] != '.' && path[1] != '-');
  343.  
  344. #elif defined(__EMX__) || defined(WIN32)
  345.   //---------- OS/2+EMX and Win32 ----------
  346.   return path[0] == '/' || path[0] == '\\' || path[1] == ':';
  347.  
  348. #elif defined(ACORN)
  349.   //---------- RISCOS ----------
  350.   return path[0] == '$';
  351.  
  352. #elif defined(MACOS)
  353.   //---------- MacOS ----------
  354.   return path[0] != ':';
  355.  
  356. #else
  357.   //---------- Unix ----------
  358.   return path[0] == '/';
  359. #endif
  360. }
  361.  
  362. GString *makePathAbsolute(GString *path) {
  363. #ifdef VMS
  364.   //---------- VMS ----------
  365.   char buf[PATH_MAX+1];
  366.  
  367.   if (!isAbsolutePath(path->getCString())) {
  368.     if (getcwd(buf, sizeof(buf))) {
  369.       path->insert(0, buf);
  370.     }
  371.   }
  372.   return path;
  373.  
  374. #elif defined(WIN32)
  375.   //---------- Win32 ----------
  376.   char buf[_MAX_PATH];
  377.   char *fp;
  378.  
  379.   buf[0] = '\0';
  380.   if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
  381.     path->clear();
  382.     return path;
  383.   }
  384.   path->clear();
  385.   path->append(buf);
  386.   return path;
  387.  
  388. #elif defined(ACORN)
  389.   //---------- RISCOS ----------
  390.   path->insert(0, '@');
  391.   return path;
  392.  
  393. #elif defined(MACOS)
  394.   //---------- MacOS ----------
  395.   path->del(0, 1);
  396.   return path;
  397.  
  398. #else
  399.   //---------- Unix and OS/2+EMX ----------
  400.   struct passwd *pw;
  401.   char buf[PATH_MAX+1];
  402.   GString *s;
  403.   char *p1, *p2;
  404.   int n;
  405.  
  406.   if (path->getChar(0) == '~') {
  407.     if (path->getChar(1) == '/' ||
  408. #ifdef __EMX__
  409.     path->getChar(1) == '\\' ||
  410. #endif
  411.     path->getLength() == 1) {
  412.       path->del(0, 1);
  413.       s = getHomeDir();
  414.       path->insert(0, s);
  415.       delete s;
  416.     } else {
  417.       p1 = path->getCString() + 1;
  418. #ifdef __EMX__
  419.       for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
  420. #else
  421.       for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
  422. #endif
  423.       if ((n = p2 - p1) > PATH_MAX)
  424.     n = PATH_MAX;
  425.       strncpy(buf, p1, n);
  426.       buf[n] = '\0';
  427.       if ((pw = getpwnam(buf))) {
  428.     path->del(0, p2 - p1 + 1);
  429.     path->insert(0, pw->pw_dir);
  430.       }
  431.     }
  432.   } else if (!isAbsolutePath(path->getCString())) {
  433.     if (getcwd(buf, sizeof(buf))) {
  434. #ifndef __EMX__
  435.       path->insert(0, '/');
  436. #endif
  437.       path->insert(0, buf);
  438.     }
  439.   }
  440.   return path;
  441. #endif
  442. }
  443.  
  444. time_t getModTime(char *fileName) {
  445. //***** Colin Granville *****
  446. //#ifdef WIN32
  447. #if defined WIN32 || ACORN
  448. //***** end Colin Granville *****
  449.   //~ should implement this, but it's (currently) only used in xpdf
  450.   return 0;
  451. #else
  452.   struct stat statBuf;
  453.  
  454.   if (stat(fileName, &statBuf)) {
  455.     return 0;
  456.   }
  457.   return statBuf.st_mtime;
  458. #endif
  459. }
  460.  
  461. GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
  462. #if defined(WIN32)
  463.   //---------- Win32 ----------
  464.   char *s;
  465.  
  466.   if (!(s = _tempnam(getenv("TEMP"), NULL))) {
  467.     return gFalse;
  468.   }
  469.   *name = new GString(s);
  470.   free(s);
  471.   if (ext) {
  472.     (*name)->append(ext);
  473.   }
  474.   if (!(*f = fopen((*name)->getCString(), mode))) {
  475.     delete (*name);
  476.     return gFalse;
  477.   }
  478.   return gTrue;
  479. #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
  480.   //---------- non-Unix ----------
  481.   char *s;
  482.  
  483.   // There is a security hole here: an attacker can create a symlink
  484.   // with this file name after the tmpnam call and before the fopen
  485.   // call.  I will happily accept fixes to this function for non-Unix
  486.   // OSs.
  487.   if (!(s = tmpnam(NULL))) {
  488.     return gFalse;
  489.   }
  490.   *name = new GString(s);
  491.   if (ext) {
  492.     (*name)->append(ext);
  493.   }
  494.   if (!(*f = fopen((*name)->getCString(), mode))) {
  495.     delete (*name);
  496.     return gFalse;
  497.   }
  498.   return gTrue;
  499. #else
  500.   //---------- Unix ----------
  501.   char *s;
  502.   int fd;
  503.  
  504.   if (ext) {
  505. #if HAVE_MKSTEMPS
  506.     if ((s = getenv("TMPDIR"))) {
  507.       *name = new GString(s);
  508.     } else {
  509.       *name = new GString("/tmp");
  510.     }
  511.     (*name)->append("/XXXXXX")->append(ext);
  512.     fd = mkstemps((*name)->getCString(), strlen(ext));
  513. #else
  514.     if (!(s = tmpnam(NULL))) {
  515.       return gFalse;
  516.     }
  517.     *name = new GString(s);
  518.     (*name)->append(ext);
  519.     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
  520. #endif
  521.   } else {
  522. #if HAVE_MKSTEMP
  523.     if ((s = getenv("TMPDIR"))) {
  524.       *name = new GString(s);
  525.     } else {
  526.       *name = new GString("/tmp");
  527.     }
  528.     (*name)->append("/XXXXXX");
  529.     fd = mkstemp((*name)->getCString());
  530. #else // HAVE_MKSTEMP
  531.     if (!(s = tmpnam(NULL))) {
  532.       return gFalse;
  533.     }
  534.     *name = new GString(s);
  535.     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
  536. #endif // HAVE_MKSTEMP
  537.   }
  538.   if (fd < 0 || !(*f = fdopen(fd, mode))) {
  539.     delete *name;
  540.     return gFalse;
  541.   }
  542.   return gTrue;
  543. #endif
  544. }
  545.  
  546. GBool executeCommand(char *cmd) {
  547. #ifdef VMS
  548.   return system(cmd) ? gTrue : gFalse;
  549. #else
  550.   return system(cmd) ? gFalse : gTrue;
  551. #endif
  552. }
  553.  
  554. char *getLine(char *buf, int size, FILE *f) {
  555.   int c, i;
  556.  
  557.   i = 0;
  558.   while (i < size - 1) {
  559.     if ((c = fgetc(f)) == EOF) {
  560.       break;
  561.     }
  562.     buf[i++] = (char)c;
  563.     if (c == '\x0a') {
  564.       break;
  565.     }
  566.     if (c == '\x0d') {
  567.       c = fgetc(f);
  568.       if (c == '\x0a' && i < size - 1) {
  569.     buf[i++] = (char)c;
  570.       } else if (c != EOF) {
  571.     ungetc(c, f);
  572.       }
  573.       break;
  574.     }
  575.   }
  576.   buf[i] = '\0';
  577.   if (i == 0) {
  578.     return NULL;
  579.   }
  580.   return buf;
  581. }
  582.  
  583. //------------------------------------------------------------------------
  584. // GDir and GDirEntry
  585. //------------------------------------------------------------------------
  586.  
  587. GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
  588. #ifdef VMS
  589.   char *p;
  590. #elif defined(WIN32)
  591.   int fa;
  592.   GString *s;
  593. #elif defined(ACORN)
  594. #else
  595.   struct stat st;
  596.   GString *s;
  597. #endif
  598.  
  599.   name = new GString(nameA);
  600.   dir = gFalse;
  601.   if (doStat) {
  602. #ifdef VMS
  603.     if (!strcmp(nameA, "-") ||
  604.     ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
  605.       dir = gTrue;
  606. #elif defined(ACORN)
  607. #else
  608.     s = new GString(dirPath);
  609.     appendToPath(s, nameA);
  610. #ifdef WIN32
  611.     fa = GetFileAttributes(s->getCString());
  612.     dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
  613. #else
  614.     if (stat(s->getCString(), &st) == 0)
  615.       dir = S_ISDIR(st.st_mode);
  616. #endif
  617.     delete s;
  618. #endif
  619.   }
  620. }
  621.  
  622. GDirEntry::~GDirEntry() {
  623.   delete name;
  624. }
  625.  
  626. GDir::GDir(char *name, GBool doStatA) {
  627.   path = new GString(name);
  628.   doStat = doStatA;
  629. #if defined(WIN32)
  630.   GString *tmp;
  631.  
  632.   tmp = path->copy();
  633.   tmp->append("/*.*");
  634.   hnd = FindFirstFile(tmp->getCString(), &ffd);
  635.   delete tmp;
  636. #elif defined(ACORN)
  637. #elif defined(MACOS)
  638. #else
  639.   dir = opendir(name);
  640. #ifdef VMS
  641.   needParent = strchr(name, '[') != NULL;
  642. #endif
  643. #endif
  644. }
  645.  
  646. GDir::~GDir() {
  647.   delete path;
  648. #if defined(WIN32)
  649.   if (hnd) {
  650.     FindClose(hnd);
  651.     hnd = NULL;
  652.   }
  653. #elif defined(ACORN)
  654. #elif defined(MACOS)
  655. #else
  656.   if (dir)
  657.     closedir(dir);
  658. #endif
  659. }
  660.  
  661. GDirEntry *GDir::getNextEntry() {
  662.   GDirEntry *e;
  663.  
  664. #if defined(WIN32)
  665.   e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
  666.   if (hnd  && !FindNextFile(hnd, &ffd)) {
  667.     FindClose(hnd);
  668.     hnd = NULL;
  669.   }
  670. #elif defined(ACORN)
  671. #elif defined(MACOS)
  672. #elif defined(VMS)
  673.   struct dirent *ent;
  674.   e = NULL;
  675.   if (dir) {
  676.     if (needParent) {
  677.       e = new GDirEntry(path->getCString(), "-", doStat);
  678.       needParent = gFalse;
  679.       return e;
  680.     }
  681.     ent = readdir(dir);
  682.     if (ent) {
  683.       e = new GDirEntry(path->getCString(), ent->d_name, doStat);
  684.     }
  685.   }
  686. #else
  687.   struct dirent *ent;
  688.   e = NULL;
  689.   if (dir) {
  690.     ent = readdir(dir);
  691.     if (ent && !strcmp(ent->d_name, ".")) {
  692.       ent = readdir(dir);
  693.     }
  694.     if (ent) {
  695.       e = new GDirEntry(path->getCString(), ent->d_name, doStat);
  696.     }
  697.   }
  698. #endif
  699.  
  700.   return e;
  701. }
  702.  
  703. void GDir::rewind() {
  704. #ifdef WIN32
  705.   GString *tmp;
  706.  
  707.   if (hnd)
  708.     FindClose(hnd);
  709.   tmp = path->copy();
  710.   tmp->append("/*.*");
  711.   hnd = FindFirstFile(tmp->getCString(), &ffd);
  712. #elif defined(ACORN)
  713. #elif defined(MACOS)
  714. #else
  715.   if (dir)
  716.     rewinddir(dir);
  717. #ifdef VMS
  718.   needParent = strchr(path->getCString(), '[') != NULL;
  719. #endif
  720. #endif
  721. }
  722.